package game.socket;

import game.action.BaseAction;
import game.system.UserImp;
import game.utils.ActionUtils;
import game.utils.UuidUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

public class GameThread extends Thread{
	private static Logger log = Logger.getLogger(GameThread.class);
	private final String POLICY_WEB = "<policy-file-request/>";
	private final String POLICY_APP = "<policy-file-xxquest/>";
	private final String SPLIT_HEAD = "\\?";
	private final String POLICY_XML = "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\""+GameServer.getPort()+"\" /></cross-domain-policy>";
	
	private static Map<String, GameThread> gameThreads = new HashMap();
	private String uuid;//唯一标示
	private Socket socket;
	private BufferedReader reader;
	private BufferedWriter writer;
	private boolean policyValidate = false;
	
	private UserImp user;//用户
	
	//防止循环攻击
	private static final int dosTimeout = 10;//超时间隔 毫秒
	private static final int dosCount = 10;//间隔数
	private int dosIndex = 0;//连续时间段内请求
	private long lastRequestTime = 0l;//记录上一次请求时间
	
	/**
	 * 校验是否是循环攻击
	 * @return
	 */
	public boolean dosValidate(){
		long curr = System.currentTimeMillis();
		dosIndex = (curr-lastRequestTime > dosTimeout)?dosIndex+1:0;
		lastRequestTime = curr;
		return dosIndex>dosCount?false:true;
	}

	public UserImp getUser() {
		return user;
	}

	public void setUser(UserImp user) {
		this.user = user;
	}

	/**
	 *校验是否是安全校验
	 * @return
	 * @throws IOException
	 */
	private boolean policyValidate() throws IOException{
		char[] cs = new char[22];
		this.getReader().read(cs, 0, 22);
		String pstr = new String(cs);
		log.debug("policyValidate():"+pstr);
		if(POLICY_WEB.equals(pstr)){
			log.debug("WEB访问安全校验");
			this.send(POLICY_XML);
			return true;
		}
		if(POLICY_APP.equals(pstr)){
			log.debug("APP访问安全校验");
			this.send("start");
		}
		return false;
	}
	
	public void run(){
		try {
			this.addGameThreads(this);
			this.getWriter();
			this.getReader();
			if(policyValidate()){//安全校验
				return ;
			}
			String msg = null;
			String[] msgs = null;
			BaseAction action = null;
			while((msg = this.reader.readLine()) != null){
				this.lastRequestTime = System.currentTimeMillis();//最后访问时间
				if(msg.length()<1){continue;}//空字符过滤
				try {
					log.debug("client msg:"+msg);
					msgs = msg.split(SPLIT_HEAD);
					action = BaseAction.getAction(msgs[0]);
					if(action==null){//无效的Action
						this.send(msgs[0]+"?error=not_action");continue;
					}
					action.setHead(msgs[0]);//请求头
					if(action.isValidataLogin() && this.getUser()==null){//访问资源需要登录
						this.send(msgs[0]+"?error=not_login");continue;
					}
					action.setGameThread(this);
					if(msgs.length == 2){//设置参数
						action.setParams(ActionUtils.getParamMap(msgs[1]));
						action.initParams();
					}
					if(!action.validate()){//访问资源校验失败
						this.send(msgs[0]+"?error=validata");continue;
					}
					action.execute();//执行Action
					//if(action != null && action.getDbUtil() != null){//回收数据库资源
					//	action.getDbUtil().commit();
					//}
				} catch (Exception e) {
					if(action != null && action.getDbUtil() != null){//数据库回滚
						action.getDbUtil().rollback();
					}
					log.error("异常",e);
					this.send(msgs[0]+"?error=exception");
				}
				//if(action != null && action.getDbUtil() != null){//回收数据库资源
				//	action.getDbUtil().close();
				//}
				action = null;
				log.debug("执行消耗:"+(System.currentTimeMillis()-this.lastRequestTime)+"毫秒   msg:"+msg);
			}
		} catch (SocketException e) {
			log.debug("用户退出异常", e);
		}  catch (NullPointerException e) {
			log.debug("用户退出异常", e);
		} catch (Exception e) {
			log.error("异常", e);
		}finally{
			log.debug("用户退出");
			this.close();//关闭以及回收资源
		}
	}
	
	public void send(String msg){
		if(msg==null){
			return ;
		}
		try {
			this.writer.write(msg+"\0");
			this.writer.flush();
			log.debug("send:"+msg);
		} catch (IOException e) {
			log.error("异常", e);
		}
	}
	
	public void close(){
		if(user != null){
			user.close();
		}
		
		try {
			this.reader.close();
			this.writer.close();
			this.socket.close();
		} catch (IOException e) {
			log.error("异常",e);
		}
		this.reader = null;
		this.writer = null;
		this.socket = null;
		this.user = null;
		GameThread.removeGameThreads(this.uuid);
		this.uuid = null;
	}
	
	public GameThread(Socket socket){
		this.socket = socket;
	}
	
	public static Map<String, GameThread> getGameThreads() {
		return gameThreads;
	}
	public static GameThread getGameThread(String uuid) {
		return gameThreads.get(uuid);
	}
	public static void addGameThreads(GameThread gameThread) {
		if(gameThread == null){
			return ;
		}
		if(gameThread.getUuid() == null){
			gameThread.setUuid(UuidUtils.getUuid());
		}
		gameThreads.put(gameThread.getUuid(), gameThread);
	}
	
	public static GameThread removeGameThreads(GameThread gameThread) {
		if(gameThread == null){
			return null;
		}
		return gameThreads.remove(gameThread.getUuid());
	}
	public static GameThread removeGameThreads(String uuid) {
		return gameThreads.remove(uuid);
	}
	
	public Socket getSocket() {
		return socket;
	}
	public BufferedReader getReader() throws IOException {
		if(this.reader == null){
			InputStreamReader isr = new InputStreamReader(this.socket.getInputStream());
			this.reader = new BufferedReader(isr);
			isr = null;
		}
		return this.reader;
	}
	public BufferedWriter getWriter() throws IOException {
		if(this.writer == null){
			OutputStreamWriter osw = new OutputStreamWriter(this.socket.getOutputStream());
			this.writer = new BufferedWriter(osw);
			osw = null;
		}
		return this.writer;
	}

	public String getUuid() {
		return uuid;
	}

	public void setUuid(String uuid) {
		this.uuid = uuid;
	}

	public long getLastRequestTime() {
		return lastRequestTime;
	}
	
	
}
